define ['fizz', 'view/BootstrapView', 'knockback', 'knockout'],  (fizz, BootstrapView, kb, ko) ->
  class CrudView extends BootstrapView
  
    # Events.
    events: {
      'submit form': 'submit',
      'click button.cancel': 'cancel',
      'click button.return': 'cancel',
      'click .specificAction': 'specificAction'
    }
    
    constructor: ->
      super()
      # Model instance. Override it with your own.
      @model = null
      # Collection instance. Override it with your own.
      @collection = null
      # Success and error messages (or codes). Override it with your own
      @addSuccessMessage = null
      @addErrorMessage = null
      @editSuccessMessage = null
      @editErrorMessage = null
      @deleteSuccessMessage = null
      @deleteErrorMessage = null
     
    # Render the template.
    renderTemplate: (params = {}) ->
      if _.isObject params.model
        @model = params.model
      if _.isObject params.collection
        @collection = params.collection
          
      if params.action is 'add'
        if _.isObject @collection
          @model = new @collection.model()
        else if _.isObject @model
          @model.clear()
      else
        unless _.isObject @model
          @model = new @collection.model() if _.isObject @collection
 
      if _.isObject @model
        if _.isUndefined params.id
          @$el.html @template {model: @model, messages: @messages, action: @action, params: params}
          if @action is 'view' or @action  is 'delete'
            @$el.find('input').attr 'disabled', 'disabled'
            @$el.find('textarea').attr 'disabled', 'disabled'
            @$el.find('select').attr 'disabled', 'disabled'
          @bindModel params
        else
          @model.set 'id', params.id
          @model.fetch {
            cache: false,
            success: (model) =>
              @$el.html @template {model: model, messages: @messages, action: @action, params: params}
              if @action is 'view' or @action  is 'delete'
                @$el.find('input').attr 'disabled', 'disabled'
                @$el.find('textarea').attr 'disabled', 'disabled'
                @$el.find('select').attr 'disabled', 'disabled'
              @bindModel params
          } 
        
    # bind the model.
    bindModel: (params) ->
      if _.isObject @viewModel
        @viewModel.destroy
      @viewModel = kb.viewModel @model
      ko.applyBindings @viewModel, @$el[0]
      
    submit: (e) ->
      @mediator.publish 'message', 'clear'
      switch @action
        when 'add'
          @add()
        when 'edit'
          @edit()
        when 'delete'
          @del()
          
    cancel: (e) ->
      @mediator.publish 'message', 'clear'
      fizz.utils.navigate @routeToNavigate
      @remove()
      
    edit: () ->
      @saveFromForm()

    add: () ->
      @saveFromForm()

    saveFromForm: () ->
      unless @model.save {}, {
        success: () => @success(),
        error: () => @error()
      }
        @error @model.validationError
            
    del: () ->
      @model.destroy
        dataType: 'text'
        success: =>
          @success()
        error: =>
          @error()

    success: () ->
      code = null
      switch @action
        when 'add'
          code = @addSuccessMessage
        when 'edit'
          code = @editSuccessMessage
        when 'delete'
          code = @deleteSuccessMessage
      @mediator.publish 'message', 'info', code, @model.toString()
      fizz.utils.navigate @routeToNavigate
      @remove()

    error: (errors) ->
      if _.isArray(errors)
        _.each errors, (error) =>
          if _.isString(error)
            @mediator.publish 'message', 'error', error
          else if _.isObject(error)
            @mediator.publish 'message', 'error', error.message
      else if _.isString(errors)
        @mediator.publish 'message', 'message', 'error', errors
      else
        code = null
        switch @action
          when 'add'
            code = @addErrorMessage
          when 'edit'
            code = @editErrorMessage
          when 'delete'
            code = @deleteErrorMessage
        @mediator.publish 'message', 'error', code

    specificAction: (e) ->
